import { FileItemModel } from '@/ts/base/model';
import { IDirectory } from '../directory';
import { ISysFileInfo } from '../systemfile';
import { ICompany } from '../..';
import { FileFilter, filters, GroupNames } from './FileFilter';

export interface ISpecialFolder {
  spaceDirectory: IDirectory;
  allFiles: ISysFileInfo[];
  /** 启动后台加载文件信息 */
  startLoadFiles(options: ILoadFileOptions): void;
  applyFilter(groupName: GroupNames | '', searchText?: string): ISysFileInfo[];
}

export interface ILoadFileOptions {
  onFoundFiles: (files: WithPath<ISysFileInfo>[], finished: boolean) => void;
  onNextDirectory?: (directory: IDirectory) => void;
  onError: (error: Error) => void;
  cancelToken?: AbortSignal;
}

export type WithPath<T> = T & { filePath?: string };

export default  class SpecialFolder implements ISpecialFolder
{
  constructor(directory: IDirectory) {
    this.spaceDirectory = directory;
  }

  spaceDirectory: IDirectory;
  allFiles: ISysFileInfo[] = [];
  allDirectories: IDirectory[] = [];

  fileLoaded = false;

  filterMap = filters.reduce<Dictionary<FileFilter<any>>>(
    (acc, filter) => {
      acc[filter.groupName] = filter;
      return acc;
    },
    {},
  );

  async startLoadFiles(options: ILoadFileOptions, reload = false) {
    const signal = options.cancelToken ?? new AbortSignal();
    const checkAbort = () => {
      if (signal.aborted) {
        signal.removeEventListener('abort', checkAbort);
        options.onError(new Error(signal.reason || '操作被取消'));
      }
    };

    const loadSpaceDirectory = async (directory: IDirectory) => {
      await directory.resource.preLoad(reload);

      for await (const directories of this.loadAllDirectory(directory, '', reload)) {
        this.allDirectories.push(...directories);
        checkAbort();
        for (const dir of directories) {
          options.onNextDirectory?.(dir);
          let files = await dir.loadFiles(reload) as WithPath<ISysFileInfo>[];
          // files = this.fileFilter(files);
          for (const f of files) {
            f.filePath = dir.filePath + (dir.filePath == '/' ? '' : '/') + f.metadata.name;
          }
          this.allFiles.push(...files);
          options.onFoundFiles(files, false);
          checkAbort();
        }
      }
    };

    try {
      checkAbort();
      signal.addEventListener('abort', checkAbort);

      await loadSpaceDirectory(this.spaceDirectory);

      // if (this.spaceDirectory.target.typeName == '单位') {
      //   const company = this.spaceDirectory.target as ICompany;
      //   await company.loadGroups();
      //   for (const group of company.groups) {
      //     checkAbort();
      //     await loadSpaceDirectory(group.directory);
      //   }        
      // }

      options.onFoundFiles([], true);
    } catch (error: any) {
      options.onError(error);
    }
  }

  async *loadAllDirectory(
    directory: WithPath<IDirectory>,
    parent: string,
    reload: boolean = false,
  ): AsyncGenerator<WithPath<IDirectory>[]> {
    directory.filePath = parent || '/';
    yield [directory];

    const dirs = await directory.standard.loadDirectorys(reload);
    for (const item of dirs) {
      yield* this.loadAllDirectory(item, parent + '/' + item.metadata.name, reload);
    }

    // 不查应用，因为应用里不能放文件
    // const apps = await directory.standard.loadApplications(reload);
    // for (const item of apps) {
    //   yield* this.loadAllDirectory(item as any, reload);
    // }
  }


  applyFilter(groupName: GroupNames | '', searchText = '') {
    let ret = this.allFiles;
    if (groupName) {
      ret = this.filterMap[groupName]?.filter(ret) ?? [];
    }
    if (searchText) {
      ret = ret.filter((file) => file.name.includes(searchText));
    }
    return ret;
  }
}
